package cn.zj.smart.util;

import cn.zj.smart.util.bean.JavaDoc;
import com.google.common.io.Files;
import org.jboss.forge.roaster.Roaster;
import org.jboss.forge.roaster.model.JavaType;
import org.jboss.forge.roaster.model.source.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.File;
import java.io.IOException;
import java.net.URL;
import java.nio.charset.Charset;
import java.util.HashMap;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * java注释解析工具
 * 为了解决和让
 * @author xi.yang
 * @create 2019-08-16 17:42
 **/
public class JavaDocUtil {
    public static final Logger log = LoggerFactory.getLogger(JavaDocUtil.class);
    private static final Pattern FIND_JAR_PATTERN = Pattern.compile("/WEB-INF/lib/(\\S+)\\.jar!");
    private static final Pattern FIND_NAME_PATTERN = Pattern.compile("(\\S+)-[\\d]+\\.");
    /**
     *
     */
    private static String apiWorkspace = "";
    private static String[] libWorkspaces = {};
    /**
     * 初始化参数
     *
     * @param apiWorkspaceParam
     * @param libWorkspacesParam
     */
    public static void initParam(String apiWorkspaceParam, String[] libWorkspacesParam) {
        apiWorkspace = apiWorkspaceParam;
        libWorkspaces = libWorkspacesParam;
    }

    private static String getClassSourcePath(Class<?> clz) {
        URL url = clz.getResource("/" + clz.getName().replace('.', '/') + ".class");
        String classPath = url.getFile();
        // 获取开发环境，本地的源码
        String sourcePath = classPath.replaceAll("target/classes", "src/main/java");
        sourcePath = sourcePath.substring(0, sourcePath.length() - ".class".length()) + ".java";
        log.info(sourcePath);
        File sourceFile = new File(sourcePath);
        if (!sourceFile.exists()) {
            // 打包之后的，对象即可能在classes下面也可能在lib包里，获取类对应的jar包名称
            if (classPath.contains("/WEB-INF/classes!/")) {
                sourcePath = apiWorkspace;
            } else if (classPath.contains("/BOOT-INF/")) {
                sourcePath = apiWorkspace;
            } else if (classPath.contains("/WEB-INF/lib/")) {
                Matcher matcher = FIND_JAR_PATTERN.matcher(classPath);
                if (matcher.find()) {
                    sourcePath = matcher.group(1);
                    matcher = FIND_NAME_PATTERN.matcher(sourcePath);
                    if (matcher.find()) {
                        sourcePath = matcher.group(1);
                    }
                }
            } else if (classPath.contains("/BOOT-INF/lib/")) {

            }
            sourcePath = sourcePath + "/src/main/java/" + clz.getName().replace('.', '/') + ".java";
            for (String w : libWorkspaces) {
                sourceFile = new File(w + sourcePath);
                if (sourceFile.exists()) {
                    log.debug("sourcePath:{}", sourcePath);
                    return sourcePath;
                }
            }
        }
        return sourcePath;
    }

    /**
     * 根据类获取源代码的注释
     *
     * @param clz
     * @return
     */
    public static JavaDoc getClassJavaDoc(Class<?> clz) {
        JavaDoc javaDoc = new JavaDoc();
        javaDoc.setPropertyDocs(new HashMap<>());
        javaDoc.setMethodDocs(new HashMap<>());
        javaDoc.setClassName(clz.getSimpleName());
        javaDoc.setPackageName(clz.getPackage().getName());
        try {
            final String sourcePath = getClassSourcePath(clz);
            File sourceFile = new File(sourcePath);
            if (sourceFile.exists()) {
                String source = Files.asCharSource(sourceFile, Charset.forName("UTF-8")).read();// 读取源码
                JavaType<?> javaType = Roaster.parse(source); // 解析源码
                if (javaType != null) {
                    if (javaType.isClass()) {
                        JavaClassSource javaClassSource = (JavaClassSource) javaType;
                        javaDoc.setClassDoc(javaClassSource.getJavaDoc().getText());
                        List<FieldSource<JavaClassSource>> fields = javaClassSource.getFields();
                        if (fields != null) {
                            for (FieldSource<JavaClassSource> field : fields) {
                                javaDoc.getPropertyDocs().put(field.getName(), field.getJavaDoc().getText());
                            }
                        }
                        List<MethodSource<JavaClassSource>> methods = javaClassSource.getMethods();
                        if (methods != null) {
                            for (MethodSource<JavaClassSource> method : methods) {
                                javaDoc.getMethodDocs().put(method.getName(), method.getJavaDoc().getText());
                            }
                        }
                    }
                    if (javaType.isEnum()) {
                        JavaEnumSource javaEnumSource = (JavaEnumSource) javaType;
                        List<EnumConstantSource> enums = javaEnumSource.getEnumConstants();
                        if (null != enums) {
                            enums.forEach(e -> javaDoc.getPropertyDocs().put(e.getName(), e.getJavaDoc().getText()));
                        }
                    }
                }
            }
        } catch (IOException e) {
            log.info("【SWAGGER】读取源文件异常：{}", e.getMessage());
        }
        Class<?> superClass = clz.getSuperclass();
        if (superClass != null && superClass != Object.class) {
            JavaDoc superClassDoc = getClassJavaDoc(superClass);
            superClassDoc.getPropertyDocs().forEach((k, v) -> javaDoc.getPropertyDocs().putIfAbsent(k, v));
            superClassDoc.getMethodDocs().forEach((k, v) -> javaDoc.getMethodDocs().putIfAbsent(k, v));
        }
        return javaDoc;
    }

}
